package com.vhall.component.service.filter.impl;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.csv.CsvData;
import cn.hutool.core.text.csv.CsvReader;
import cn.hutool.core.text.csv.CsvRow;
import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.dao.filter.FilterWordsMapper;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.filter.FilterWordsEntity;
import com.vhall.component.entity.filter.enums.FilterWordDealTypeEnum;
import com.vhall.component.entity.filter.vo.FilterWordsImportRspVO;
import com.vhall.component.entity.filter.vo.FilterWordsListReqVO;
import com.vhall.component.entity.filter.vo.FilterWordsListRspVO;
import com.vhall.component.entity.page.vo.PageVO;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.entity.subject.enums.StatusEnum;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.exception.GlobalErrorCode;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.enums.RoomConfigStatusEnum;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.plugin.common.utils.JsonUtil;
import com.vhall.component.plugin.core.enums.SendMessageTypeEnum;
import com.vhall.component.plugin.core.service.PaasService;
import com.vhall.component.service.filter.FilterWordsRepository;
import com.vhall.component.service.filter.FilterWordsService;
import com.vhall.component.service.filter.constant.FilterConstant;
import com.vhall.component.service.room.RoomInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.vhall.component.plugin.common.exception.BizErrorCode.TYPE_INVALID_STRING;
import static com.vhall.component.plugin.common.exception.BizErrorCode.TYPE_INVALID_STR_LEN;

/**
 * @author longzhen.gong
 * @date 2021/7/2 17:34
 */

@Slf4j
@Service
public class FilterWordsServiceImpl implements FilterWordsService {

    private static final String KEYWORD = "keyword";
    private static final String MESSAGE = "message";

    @Autowired
    private FilterWordsMapper filterWordsMapper;

    @Autowired
    private FilterWordsRepository filterWordsRepository;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private RoomInnerService roomInnerService;
    @Autowired
    private PaasService paasService;
    @Autowired
    private AccountMapper accountMapper;

    /**
     * key序列化
     */
    private static final StringRedisSerializer STRING_SERIALIZER = new StringRedisSerializer();

    @Override
    public PageVO<FilterWordsListRspVO> list(FilterWordsListReqVO reqVO, Integer accountId) {

        int curPage = reqVO.getPage();
        int pageSize = reqVO.getPageSize() == null ? 10 : reqVO.getPageSize();
        Page<FilterWordsEntity> page = new Page<>(curPage, pageSize);

        page = filterWordsMapper.selectPage(page, Wrappers.<FilterWordsEntity>lambdaQuery()
                .like(StringUtils.isNotBlank(reqVO.getSearch()), FilterWordsEntity::getKeyword, reqVO.getSearch())
//                .eq(accountId != 0, FilterWordsEntity::getAccountId, accountId)
//                .eq(StringUtils.isNotBlank(reqVO.getRoomId()), FilterWordsEntity::getRoomId, reqVO.getRoomId())
//                .eq(StringUtils.isEmpty(reqVO.getRoomId()), FilterWordsEntity::getIlId, 0)
                .orderByDesc(FilterWordsEntity::getId));

        PageVO<FilterWordsListRspVO> pageVO = new PageVO<>();
        List<FilterWordsListRspVO> filterWords = page.getRecords()
                .stream()
                .map(filterWordsEntity -> {
                    FilterWordsListRspVO rspVO = new FilterWordsListRspVO();
                    BeanUtils.copyProperties(filterWordsEntity, rspVO);
                    return rspVO;
                })
                .collect(Collectors.toList());
        pageVO.setCurrentPage(Math.toIntExact(page.getCurrent()));
        pageVO.setLastPage(Math.toIntExact(page.getPages()));
        pageVO.setTotal(Math.toIntExact(page.getTotal()));
        pageVO.setData(filterWords);
        pageVO.setPerPage(Math.toIntExact(page.getSize()));
        return pageVO;
    }

    @Override
    public List<FilterWordsEntity> checkFilterWordsRepeat(String keyword, Integer accountId, String roomId) {
        List<FilterWordsEntity> filterWordsEntities;
//        if (StringUtils.isEmpty(roomId) && accountId == 0) {
//            filterWordsEntities = filterWordsMapper.selectList(
//                    Wrappers.<FilterWordsEntity>lambdaQuery()
//                            .and(wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getAccountId, 0)));
//        } else if (StringUtils.isEmpty(roomId) && accountId > 0) {
//            filterWordsEntities = filterWordsMapper.selectList(
//                    Wrappers.<FilterWordsEntity>lambdaQuery()
//                            .and(wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getAccountId, 0))
//                            .or(wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getAccountId, accountId).eq(FilterWordsEntity::getIlId, 0)));
//        } else {
//            filterWordsEntities = filterWordsMapper.selectList(
//                    Wrappers.<FilterWordsEntity>lambdaQuery()
//                            .and(wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getAccountId, 0))
//                            .or(accountId > 0, wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getAccountId, accountId).eq(FilterWordsEntity::getIlId, 0))
//                            .or(StringUtils.isNotBlank(roomId), wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword).eq(FilterWordsEntity::getRoomId, roomId)));
//        }
        filterWordsEntities = filterWordsMapper.selectList(
                Wrappers.<FilterWordsEntity>lambdaQuery()
                        .and(wrapper -> wrapper.eq(FilterWordsEntity::getKeyword, keyword)));
        return filterWordsEntities;
    }


    @Override
    public boolean checkFilterWords(String keyword) {
        int length = StringUtils.length(keyword);
        if (length < 1 || length > 50) {
            throw new BusinessException(TYPE_INVALID_STR_LEN);
        }
        String reg = "^[a-zA-Z0-9\\u4e00-\\u9fa5\\s]+$";
        if (!ReUtil.isMatch(reg, keyword)) {
            log.error("词汇校验失败{}", keyword);
            throw new BusinessException(TYPE_INVALID_STRING);
        }
        return true;
    }

    @Override
    public FilterWordsEntity create(String keyword, Integer accountId, Integer userId, String roomId) {
        delKey();
        checkFilterWords(keyword);
        keyword = StringUtils.trim(keyword);
        List<FilterWordsEntity> filterWordsEntities = checkFilterWordsRepeat(keyword, accountId, roomId);
        if (CollectionUtils.isNotEmpty(filterWordsEntities)) {
            throw new BusinessException(BizErrorCode.COMP_FILTER_REPEAT_KEY);
        }
        final RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(roomId);
        FilterWordsEntity filterWordsEntity = new FilterWordsEntity();
        filterWordsEntity.setKeyword(keyword);
        filterWordsEntity.setAccountId(accountId);
        filterWordsEntity.setUserId(userId);
        filterWordsEntity.setIlId(roomInfo != null ? roomInfo.getIlId() : null);
        filterWordsEntity.setCreatedAt(LocalDateTime.now());
        filterWordsEntity.setRoomId(roomId);
        filterWordsMapper.insert(filterWordsEntity);
        log.info("insert filterword info,{}", filterWordsEntity.toString());

        handlerCreateFilterWord(keyword, accountId, roomId);
        return filterWordsEntity;
    }

    /**
     * 创建敏感词后相关的处理操作
     *
     * @param keyword   创建时传入的关键词
     * @param accountId 用户账号
     * @param roomId    房间id
     */
    private void handlerCreateFilterWord(String keyword, Integer accountId, String roomId) {
        //设置敏感词开关
        if (StringUtils.isBlank(roomId)) {
            //账号下或全局敏感词开关

            roomInnerService.insertOrUpdateRoomConfigByAccountId(accountId, StatusEnum.OPEN.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());
            List<RoomsEntityDTO> roomsEntityDTOS;
            if (Objects.isNull(accountId) || accountId == 0) {
                roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannel()).orElse(new ArrayList<>());
            } else {
                roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannelOnAccount(accountId)).orElse(new ArrayList<>());
            }
            //获取当前正在直播的房间
//        推送创建的敏感词到所有正在直播的房间
            roomsEntityDTOS.forEach(roomData -> liveUpdateFilterWord(FilterWordDealTypeEnum.CREATE.getDealType(), keyword, "", roomData.getRoomId()));
        } else {
            //房间下敏感词开关
            roomInnerService.updateConfigValueByRoomId(roomId, StatusEnum.OPEN.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());
            liveUpdateFilterWord(FilterWordDealTypeEnum.CREATE.getDealType(), keyword, "", roomId);
        }
    }


    @Override
    public Boolean update(Integer id, String keyword, String roomId, Integer accountId, Integer userId) {
        delKey();
        keyword = StringUtils.trim(keyword);
        checkFilterWords(keyword);
        List<FilterWordsEntity> filterWordsEntities = checkFilterWordsRepeat(keyword, accountId, roomId);
        if (CollectionUtils.isNotEmpty(filterWordsEntities) && filterWordsEntities.stream().anyMatch(x -> !id.equals(x.getId()))) {
            throw new BusinessException(BizErrorCode.COMP_FILTER_REPEAT_KEY);
        }
        FilterWordsEntity filterWordsEntity = filterWordsMapper.selectOne(Wrappers.<FilterWordsEntity>lambdaQuery()
                .eq(FilterWordsEntity::getId, id)
                .eq(StringUtils.isNotBlank(roomId), FilterWordsEntity::getRoomId, roomId));
        if (filterWordsEntity == null) {
            throw new BusinessException(BizErrorCode.EMPTY_DATA);
        }
        String oldFilterWord = filterWordsEntity.getKeyword();
        filterWordsEntity.setKeyword(keyword);
        filterWordsEntity.setUpdatedAt(LocalDateTime.now());
        filterWordsEntity.setAccountId(accountId);
        filterWordsEntity.setUserId(userId);
        int updateNum = filterWordsMapper.updateById(filterWordsEntity);
        boolean updateResult = updateNum > 0;
        if (updateResult) {
            handleUpdateFilterKeyword(keyword, accountId, roomId, oldFilterWord);
        }
        return updateResult;
    }

    /**
     * 更新敏感词后的处理操作
     *
     * @param keyword       更新后的敏感词
     * @param accountId     账号id
     * @param roomId        房间id
     * @param oldFilterWord 更新前的敏感词
     */
    private void handleUpdateFilterKeyword(String keyword, Integer accountId, String roomId, String oldFilterWord) {
//        实时推送到房间进行敏感词更新
        if (StringUtils.isNotBlank(roomId)) {
            liveUpdateFilterWord(FilterWordDealTypeEnum.UPDATE.getDealType(), keyword, oldFilterWord, roomId);
        } else {
            List<RoomsEntityDTO> roomsEntityDTOS;
            if (Objects.nonNull(accountId) && accountId != 0) {
                roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannelOnAccount(accountId)).orElse(new ArrayList<>());
            } else {
                roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannel()).orElse(new ArrayList<>());
            }
            roomsEntityDTOS.forEach(roomData ->
                    liveUpdateFilterWord(FilterWordDealTypeEnum.UPDATE.getDealType(), keyword, oldFilterWord, roomData.getRoomId()));
        }
    }

    @Override
    public Integer delete(String ids) {
        delKey();
        //删除前获取敏感词信息
        List<String> idList = Arrays.asList(ids.split(","));
        List<FilterWordsEntity> filterWordsList = filterWordsMapper.selectList(new LambdaQueryWrapper<FilterWordsEntity>().in(FilterWordsEntity::getId, idList));

        FilterWordsEntity filterWords = filterWordsMapper.selectOne(new LambdaQueryWrapper<FilterWordsEntity>()
                .eq(FilterWordsEntity::getId, idList.get(0)));

        //返回删除数量
        int deleteNumber = filterWordsMapper.deleteBatchIds(idList);
        //判断删除的敏感词是什么级别下的(房间下,账号下,全局)
        if (StringUtils.isBlank(filterWords.getRoomId())) {
            if (filterWords.getAccountId() == 0) {
//                全局的敏感词删除
                //查询删除后是否还有全局敏感词
                handlerAllDeleteFilterWords(filterWordsList, deleteNumber);
            } else {
//                账号下敏感词删除
                //查询删除后是否还有全局敏感词
                handlerAccountDeleteFilterWords(filterWordsList, deleteNumber, filterWords.getAccountId());
            }
        } else {
//            房间下的敏感词删除
            handlerRoomDeleteFilterWord(filterWordsList, filterWords.getRoomId(), deleteNumber);
        }
        return deleteNumber;
    }

    /**
     * 删除房间下敏感词
     *
     * @param filterWordsList 删除的敏感词列表
     * @param roomId          房间id
     * @param deleteNumber    实际删除数量
     */
    private void handlerRoomDeleteFilterWord(List<FilterWordsEntity> filterWordsList, String roomId, int deleteNumber) {
        Integer filterWordsNumber = filterWordsMapper.selectCount(new LambdaQueryWrapper<FilterWordsEntity>()
                .eq(FilterWordsEntity::getRoomId, roomId));
        if (filterWordsNumber == 0) {
            //设置房间下敏感词开关
            roomInnerService.updateConfigValueByRoomId(roomId, StatusEnum.CLOSE.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());
        }
        if (deleteNumber > 0) {
            filterWordsList.forEach(filterWord -> liveUpdateFilterWord(FilterWordDealTypeEnum.DELETE.getDealType(), filterWord.getKeyword(), "", filterWord.getRoomId()));
        }
    }

    /**
     * 删除全局敏感词处理任务
     *
     * @param filterWordsList 删除敏感词列表
     * @param deleteNumber    删除的数量
     */
    private void handlerAllDeleteFilterWords(List<FilterWordsEntity> filterWordsList, int deleteNumber) {
        Integer filterWordsNumber = filterWordsMapper.selectCount(new LambdaQueryWrapper<FilterWordsEntity>()
                .eq(FilterWordsEntity::getAccountId, 0)
                .isNull(FilterWordsEntity::getRoomId));
        if (filterWordsNumber == 0) {
            //没有则开关关闭
            roomInnerService.insertOrUpdateRoomConfigByAccountId(0, StatusEnum.CLOSE.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());
        }
        if (deleteNumber > 0) {
            List<RoomsEntityDTO> roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannel()).orElse(new ArrayList<>());
            roomsEntityDTOS.forEach(roomData -> filterWordsList.forEach(filterWord -> liveUpdateFilterWord(FilterWordDealTypeEnum.DELETE.getDealType(),
                    filterWord.getKeyword(), "", roomData.getRoomId())));
        }
    }

    /**
     * 删除用户下的敏感词处理任务
     *
     * @param filterWordsList 删除的敏感词列表
     * @param deleteNumber    删除数量
     * @param accountId       账号id
     */
    private void handlerAccountDeleteFilterWords(List<FilterWordsEntity> filterWordsList, int deleteNumber, Integer accountId) {
        Integer filterWordsNumber = filterWordsMapper.selectCount(new LambdaQueryWrapper<FilterWordsEntity>()
                .eq(FilterWordsEntity::getAccountId, accountId)
                .isNull(FilterWordsEntity::getRoomId));
        if (filterWordsNumber == 0) {
            //没有则开关关闭
            roomInnerService.insertOrUpdateRoomConfigByAccountId(accountId, StatusEnum.CLOSE.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());
        }
        if (deleteNumber > 0) {
            List<RoomsEntityDTO> roomsEntityDTOS = Optional.ofNullable(roomInnerService.listOnlineChannelOnAccount(accountId)).orElse(new ArrayList<>());
            roomsEntityDTOS.forEach(roomData -> filterWordsList.forEach(filterWord -> liveUpdateFilterWord(FilterWordDealTypeEnum.DELETE.getDealType(),
                    filterWord.getKeyword(), "", roomData.getRoomId())));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public FilterWordsImportRspVO importFile(String roomId, MultipartFile multipartFile, Integer accountId, Integer userId) {
        delKey();
        int successNum = 0;
        int failNum = 0;
        String fileName = multipartFile.getOriginalFilename();
        if (StringUtils.isBlank(fileName)) {
            throw new BusinessException(BizErrorCode.COMP_FILTER_UPLOAD_NULL);
        }
        List<Map<String, Object>> failList = new ArrayList<>();

        // 用于标识是否可以导入的敏感词，用于判断重复
        String extName = FileUtil.extName(fileName);
        Set<String> filterWordsSet = new HashSet<>();
        if ("csv".equals(extName)) {
            // 解析csv文件
            CsvReader csvReader = new CsvReader();
            try {
                InputStream is = multipartFile.getInputStream();
                InputStreamReader inputStreamReader = new InputStreamReader(is);
                CsvData csvData = csvReader.read(inputStreamReader);
                List<CsvRow> rows = csvData.getRows();
                int totalNums = rows.size();
                if (totalNums > 1000) {
                    throw new BusinessException(BizErrorCode.COMP_FILTER_IMPORT_OVERFLOW);
                }
                List<FilterWordsEntity> filterWordsEntities;
                filterWordsEntities = new ArrayList<>();
                for (int i = 0; i < totalNums; i++) {
                    String keyWord = rows.get(i).get(0);
                    // 去除csv文件的开头结尾为'\uFEFF'的字符编码
                    String prefix = "\uFEFF";
                    if (keyWord.startsWith(prefix)) {
                        keyWord = keyWord.replace(prefix, "");
                    } else if (keyWord.endsWith(prefix)) {
                        keyWord = keyWord.replace(prefix, "");
                    }
                    if (FilterConstant.TEMPLATE.equals(keyWord) || StringUtils.isBlank(keyWord)) {
                        continue;
                    }
                    keyWord = StringUtils.trim(keyWord);
                    boolean checkFilterWords = checkFilterWords(keyWord, failList, failNum);
                    if (!checkFilterWords) {
                        failNum++;
                        continue;
                    }
                    if (StringUtils.isBlank(keyWord)) {
                        throw new BusinessException(GlobalErrorCode.FAILED);
                    }
                    // 此处set用于判断当前文档中 是否有重复敏感词
                    if (filterWordsSet.contains(keyWord)) {
                        continue;
                    }
                    filterWordsSet.add(keyWord);

                    List<FilterWordsEntity> checkRepeat = checkFilterWordsRepeat(keyWord, accountId, roomId);
                    Map<String, Object> map = new HashMap<>(4);
                    if (CollectionUtils.isNotEmpty(checkRepeat)) {
                        map.put("keyword", keyWord);
                        map.put("message", "敏感词重复");
                        failList.add(map);
                        failNum++;
                        continue;
                    }


                    FilterWordsEntity filterWordsEntity = new FilterWordsEntity();
                    filterWordsEntity.setKeyword(keyWord);
                    filterWordsEntity.setAccountId(accountId);
                    filterWordsEntity.setUserId(userId);
                    filterWordsEntity.setRoomId(roomId);
                    filterWordsEntities.add(filterWordsEntity);
                    successNum++;
                    if (successNum % 100 == 0) {
                        filterWordsRepository.saveBatch(filterWordsEntities);
                        filterWordsEntities = new ArrayList<>();
                    }
                }
                filterWordsRepository.saveBatch(filterWordsEntities);
            } catch (IOException e) {
                log.error("导入excel失败", e);
                throw new BusinessException(e.getMessage());
            }
        } else {
            // 解析xlsx和xls文件
            try {
                Workbook wb = null;
                if ("xlsx".equals(extName)) {
                    wb = new XSSFWorkbook(multipartFile.getInputStream());
                } else {
                    wb = new HSSFWorkbook(multipartFile.getInputStream());
                }
                Sheet sheet = wb.getSheetAt(0);
                int totalNums = getRealRowNums(sheet);

                if (totalNums > 1000) {
                    throw new BusinessException(BizErrorCode.COMP_FILTER_IMPORT_OVERFLOW);
                }

                List<FilterWordsEntity> filterWordsEntities = new ArrayList<>();
                for (int i = 0; i < sheet.getLastRowNum() + 1; i++) {
                    Row row = sheet.getRow(i);
                    if (row == null) {
                        continue;
                    }
                    String keyWord = "";
                    Cell one = row.getCell(0);
                    if (one == null) {
                        continue;
                    }
                    if (one.getCellTypeEnum() == CellType.NUMERIC) {
                        NumberFormat nf = NumberFormat.getInstance();
                        keyWord = nf.format(one.getNumericCellValue());
                        keyWord = keyWord.replaceAll(",", "");
                    } else {
                        keyWord = one.getStringCellValue();
                        if (FilterConstant.TEMPLATE.equals(keyWord) || StringUtils.isBlank(keyWord)) {
                            continue;
                        }
                    }
                    keyWord = StringUtils.trim(keyWord);
                    boolean checkFilterWords = checkFilterWords(keyWord, failList, failNum);
                    if (!checkFilterWords) {
                        failNum++;
                        continue;
                    }
                    if (StringUtils.isBlank(keyWord)) {
                        continue;
                    }
                    // 此处set用于判断当前文档中 是否有重复敏感词
                    if (filterWordsSet.contains(keyWord)) {
                        Map<String, Object> map = new HashMap<>(4);
                        map.put("keyword", keyWord);
                        map.put("message", "敏感词重复");
                        failList.add(map);
                        failNum++;
                        continue;
                    }
                    filterWordsSet.add(keyWord);

                    List<FilterWordsEntity> checkRepeat = checkFilterWordsRepeat(keyWord, accountId, roomId);
                    Map<String, Object> map = new HashMap<>(4);
                    if (CollectionUtils.isNotEmpty(checkRepeat)) {
                        map.put("keyword", keyWord);
                        map.put("message", "敏感词重复");
                        failList.add(map);
                        failNum++;
                        continue;
                    }

                    FilterWordsEntity filterWordsEntity = new FilterWordsEntity();
                    filterWordsEntity.setKeyword(keyWord);
                    filterWordsEntity.setAccountId(accountId);
                    filterWordsEntity.setUserId(userId);
                    filterWordsEntity.setRoomId(roomId);
                    filterWordsEntities.add(filterWordsEntity);
                    successNum++;
                    if (successNum % 100 == 0) {
                        filterWordsRepository.saveBatch(filterWordsEntities);
                        filterWordsEntities = new ArrayList<>();
                    }
                }
                filterWordsRepository.saveBatch(filterWordsEntities);
            } catch (IOException e) {
                log.error("导入excel失败", e);
                throw new BusinessException(e.getMessage());
            }
        }
        //设置非房间级敏感词开关
        roomInnerService.insertOrUpdateRoomConfigByAccountId(accountId, StatusEnum.OPEN.getValue(), RoomConfigStatusEnum.FILTER_WORDS_STATUS.getValue());

        FilterWordsImportRspVO filterWordsImportRspVO = new FilterWordsImportRspVO();
        filterWordsImportRspVO.setFailList(failList);
        filterWordsImportRspVO.setFailNum(failNum);
        filterWordsImportRspVO.setSuccessNum(successNum);
        return filterWordsImportRspVO;
    }

    /**
     * 计算实际行数
     *
     * @param sheet
     * @return int
     */
    private int getRealRowNums(Sheet sheet) {
        int realRow = 0;
        for (int i = 0; i <= sheet.getLastRowNum() + 1; i++) {
            //i从1开始，不判断第一行标题行
            Row row = sheet.getRow(i);
            if (row == null) {
                continue;
            }
            Cell cell = row.getCell(0);
            if (cell == null) {
                continue;
            }
            if (cell.getCellTypeEnum() == CellType.STRING && "敏感词(支持中文、英文、数据、空格，不支持特殊字符)".equals(cell.getStringCellValue())) {
                continue;
            }
            String value = "";
            if (cell.getCellTypeEnum() == CellType.NUMERIC) {
                NumberFormat nf = NumberFormat.getInstance();
                value = nf.format(cell.getNumericCellValue());
            } else if (cell.getCellTypeEnum() == CellType.STRING) {
                value = cell.getStringCellValue().trim();
            }
            if (StringUtils.isNotEmpty(value)) {
                realRow++;
            }

        }
        return realRow;
    }

    private boolean checkFilterWords(String keyword, List<Map<String, Object>> failList, int failNum) {
        int length = StringUtils.length(keyword);
        HashMap<String, Object> map = new HashMap<>(16);
        if (length < 1 || length > 50) {
            map.put(KEYWORD, keyword);
            map.put(MESSAGE, TYPE_INVALID_STR_LEN.getMsg());
            map.put("key", TYPE_INVALID_STR_LEN.getKey());
            failList.add(map);
            log.error("敏感词长度太长,校验失败,{}", failList);
            return false;

        }
        String reg = "^[a-zA-Z0-9\\u4e00-\\u9fa5\\s]+$";
        if (!ReUtil.isMatch(reg, keyword)) {
            map.put(KEYWORD, keyword);
            map.put(MESSAGE, TYPE_INVALID_STRING.getMsg());
            map.put("key", TYPE_INVALID_STRING.getKey());
            failList.add(map);
            log.error("词汇校验失败，{}", failList);
            return false;
        }
        String oldKeyword = keyword;
        keyword = keyword.replaceAll(" ", "");
        String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？]|\n|\r|\t";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(keyword);

        if (m.find()) {
            map.put(KEYWORD, oldKeyword);
            map.put(MESSAGE, TYPE_INVALID_STRING.getMsg());
            map.put("key", TYPE_INVALID_STRING.getKey());
            failList.add(map);
            log.error("词汇校验失败，{}", failList);
            return false;
        }

        return true;
    }


    private void delKey() {
        Set<String> members = redisTemplate.opsForSet().members(RedisKey.FILTER_WORDS_ILID_SET);
        assert members != null;
        redisTemplate.executePipelined((RedisCallback<?>) connection -> {
            for (String single : members) {
                connection.del(STRING_SERIALIZER.serialize(RedisKey.FILTER_WORDS_CACHE_KEY + 1));
            }
            return null;
        });
    }

    /**
     * 实时更新敏感词
     *
     * @param dealType      处理类型    0-新增，1-更新，2-删除
     * @param keyword       敏感词
     * @param oldFilterWord 修改前的敏感词（编辑情况存在）
     * @param roomId        房间ID
     */
    @Override
    public void liveUpdateFilterWord(String dealType, String keyword, String oldFilterWord, String roomId) {
        if (StringUtils.isNotBlank(roomId)) {
            RoomsEntityDTO room = Optional.ofNullable(roomInnerService.getRoomInfo(roomId)).
                    orElseThrow(() -> new BusinessException(BizErrorCode.EMPTY_ROOM));
            JSONObject object = new JSONObject();
            object.put("type", SendMessageTypeEnum.FILTER_WORD_UPDATE.getType());
            object.put("deal_type", dealType);
            object.put("keyword", keyword);
            object.put("old_filter", oldFilterWord);
            String body = JsonUtil.toJsonString(object);
            String channelId = room.getChannelId();
            paasService.sendMessage(channelId, body);
            log.info("实时更新敏感词调用--channelId:{},body:{}", channelId, body);
        }
    }

}
